#ifndef __CO_UTILS_H__
#define __CO_UTILS_H__

#include <map>

#include <string>
#include <iostream>
#include <sstream>

#include "common/log_adapter.h"

class CoUtils
{
public:
	template <class T>
    static T get_co_env(const std::string& key, T def_value) {
		char* p = getenv(key.c_str());
		if (!p) {
			return def_value;
		}
		std::istringstream iss(p);
		T env_value;
		iss >> env_value;
		return env_value;
	}

    static int getcid();
};

enum {
    LOG_TAG_TID = 0X10,
    LOG_TAG_CID = 0X20,
};

template <class T>
class LogAdapterCo : public LogAdapter<T>
{
public:
    LogAdapterCo() {
        LogAdapter<T>::_log_tags |= (LOG_TAG_TID | LOG_TAG_CID); 
    }

protected:
    void get_tag_values(
        const LogContext& ctx, 
        std::map<int, std::pair<std::string, std::string>>& tag_values
    )
    {
   	    LogAdapter<T>::get_tag_values(ctx, tag_values);
    	tag_values[LOG_TAG_TID] =
        	std::make_pair("tid", std::to_string(CommonUtils::gettid()));
    	tag_values[LOG_TAG_CID] =
        	std::make_pair("cid", std::to_string(CoUtils::getcid())); 
    }
};

#ifdef LOCK_GUARD_DEBUG
#define LOCK_GUARD(module, obj) LockGuardDebug<module> lock((obj))
#else
#define LOCK_GUARD(module, obj) std::lock_guard<module> lock((obj))
#endif

template <class MUTEX>
class LockGuardDebug : public LogAdapterCo<MUTEX>
{
public:
	explicit LockGuardDebug(MUTEX& mu, const std::string& func = "", int line = -1) : _mu(mu), _func(func), _line(line) {
		LOG_DEBUG("lock ready, ptr:%p, func:%s, line:%d", &_mu, _func.c_str(), _line);
		_mu.lock();
		LOG_DEBUG("lock succeed, ptr:%p, func:%s, line:%d", &_mu, _func.c_str(), _line);
	}

	~LockGuardDebug() noexcept {
		LOG_DEBUG("unlock ready, ptr:%p, func:%s, line:%d", &_mu, _func.c_str(), _line);
		_mu.unlock();
		LOG_DEBUG("unlock succeed, ptr:%p, func:%s, line:%d", &_mu, _func.c_str(), _line);
	}

	LockGuardDebug(const LockGuardDebug&) = delete;
	LockGuardDebug& operator=(const LockGuardDebug&) = delete;

private:
	MUTEX& _mu;
	std::string _func;
	int			_line;
};

#endif

